//
//  MyDocument.m
//  iMed
//
//  Created by Barry Press on 8/14/09.
//  Copyright Barry Press 2009 . All rights reserved.

//	Modified 12/16/2009, B. Press, fix margins on printout
//			  1/14/2011, B. Press, filter by date on iPad import to ignore 
//								   records we should already have, mark doc modded
//								   due to that import

//
#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#import "MyDocument.h"
#import "DataSet.h"
#import "ForecastSchedule.h"

@interface MyDocument()

- (void)createHistoryForRX:(RX*)rx atTime:(NSDate*)aTime;
- (void) csvOutToFile:(FILE*)fOut T:(NSDate*)t A:(NSDate*)a B:(NSDate*)b C:(NSDate*)c D:(NSDate*)d;
- (const char*) csvOutFormatInterval:(NSDate*)v;
- (NSString*) dateToNSString:(NSDate*)t;
- (NDCitem*) findSelectedNDCEntry;
- (NSArray*) findSelectedRXEntries;
- (NSString*)getImportData:(NSError**)e;
- (BOOL) keepBackupFile;
- (void)loadFileData;
- (void) makeLatestHistoryVisible;
- (NSWindow*) myWindow;
- (void) preloadRX;
- (void) preloadNDC;
- (void) printForecastToView:(NSView*)v;
- (NSPrintOperation*) printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError;
- (void) processHistoryCreationAtTime:(NSDate*)aTime;
- (IBAction)readiPadStreamMenu:(id)sender;
- (void) setEditedStateToBe:(BOOL)state;
- (void) setEditedStatus;
- (void) showCustomSheet: (NSWindow *)window;
- (void) timerFireMethod:(NSTimer*)theTimer;
- (void) updateForecastForRX:(RX*)anRx;
- (void) updateForecast; 
- (BOOL) writeCSVToFile:(NSString*)aPath detail:(BOOL)bDetail counts:(BOOL)bCounts stream:(BOOL)bStream;


@end

@implementation MyDocument

#pragma mark -
#pragma mark Button response methods 
// =============================================================================
// ---------------------------------------------- pushCreateHistoryButton ------
- (IBAction)pushCreateHistoryButton:(id)sender
{
	[self processHistoryCreationAtTime:[NSDate date]];
	[self setEditedStatus];
}

// ---------------------------------------------- pushCreateNDCButton ----------
- (IBAction)pushCreateNDCButton:(id)sender
{
	NDCitem* ndc = [dataset createNDC];
	[ndcController addObject:ndc];
	[ndcList reloadData];
	[self setEditedStatus];
}

// ---------------------------------------------- pushCreateRXButton -----------
- (IBAction)pushCreateRXButton:(id)sender
{
	NDCitem* ndc = [self findSelectedNDCEntry];
	if (ndc != nil) {
		RX* rx = [dataset createRXForNDC:ndc
						   writtenOnDate:[NSDate date] 
							filledOnDate:[NSDate date]];
		[rxController addObject:rx];
		[rxList reloadData];
	}
	[self setEditedStatus];
}

// ---------------------------------------------- pushUpdateButton -------------
- (IBAction)pushUpdateButton:(id)sender
{
	[self updateForecast];
	[self setEditedStatus];
}

// ---------------------------------------------- pushEnableButton -------------
- (IBAction)pushEnableButton:(id)sender
{
	if (bTimerEnabled) {
		[enableButton setTitle:@"Enable"];
	}
	else {
		[enableButton setTitle:@"Disable"];
	}
	bTimerEnabled = !bTimerEnabled;
}

// ---------------------------------------------- pushStopButton ---------------
- (IBAction)pushStopButton:(id)sender;
{
	[sAlarm stop];
	NSShowAnimationEffect(NSAnimationEffectPoof, [NSEvent mouseLocation], NSZeroSize, NULL, NULL, NULL);
	if (bTimerEnabled) {
		[self pushEnableButton:self];
	}
}

// ---------------------------------------------- pushAtDateButton -------------
- (IBAction)pushAtDateButton:(id)sender;
{
	if ([sender isKindOfClass:[NSButton class]]) {
		NSDate* theDate = [datePicker dateValue];
		[self processHistoryCreationAtTime:theDate];
		[self setEditedStatus];
	}
}

// ---------------------------------------------- pushAutoButton ---------------
- (IBAction)pushAutoButton:(id)sender
{
	[self updateForecast];
	NSArray* rxs = [dataset getReadyRXArray];
	[rxController setSelectedObjects:rxs];
	if ([rxs count] > 0) {
		[self processHistoryCreationAtTime:[NSDate date]];
		[self setEditedStatus];
	}
}

// ---------------------------------------------- pushForecastButton -----------
- (IBAction)pushForecastButton:(id)sender
{
	[self showCustomSheet:[self myWindow]];
}

#pragma mark -
#pragma mark Menu response methods 
// =============================================================================
// ---------------------------------------------- menuPreload ------------------
- (IBAction)menuPreload:(id)sender
{
	[self preloadNDC];
	[ndcList reloadData];
	[self preloadRX];
	[rxList reloadData];
	[self setEditedStatus];
}

#pragma mark -
#pragma mark History entry creation
// =============================================================================
// -----------------------------------------------------------------------------
- (void)createHistoryForRX:(RX*)rx atTime:(NSDate*)aTime
{
	History* h = [dataset createHistoryWithRX:rx atTime:aTime];
	if (h != nil) {
		[hController addObject:h];
		// If there is no prior history record with this rx, then the prior 
		// timestamp equals this one, and the interval is zero. Set the 
		// running interval to match.
		if ([h runninginterval] < 0)
			[h setRunninginterval:[dataset averageIntervalForRX:rx]];
		[self updateForecastForRX:rx];
	}
}

// ---------------------------------------------- processHistoryCreationAtTime -
- (void)processHistoryCreationAtTime:(NSDate*)aTime
{
	NSAssert([[dataset arrayRXlog] count] > 0, @"No RX found");
	NSArray* rxObjects = [self findSelectedRXEntries];
	for (int ix = 0; ix < [rxObjects count]; ++ix) {
		RX* rx = [rxObjects objectAtIndex:ix];
		[self createHistoryForRX:rx atTime:aTime];
	}
	[self makeLatestHistoryVisible];
}

// ---------------------------------------------- makeLatestHistoryVisible -----
- (void)makeLatestHistoryVisible
{
	NSAssert(historyList != nil, @"History list not yet built in makeLatestHistoryVisible");
	[historyList reloadData];
	[historyList scrollRowToVisible:[historyList numberOfRows]-1];
	[self updateForecast];
}

#pragma mark -
#pragma mark Push button helper routines

// =============================================================================

// ---------------------------------------------- findSelectedNDCEntry ---------
- (NDCitem*)findSelectedNDCEntry
{
	NSArray* a = [ndcController selectedObjects];
	return ([a count] > 0) ? [a  objectAtIndex:0] : nil;
}

// ---------------------------------------------- findSelectedRXEntry ----------
- (NSArray*)findSelectedRXEntries
{
	NSArray* rxObjects = [rxController selectedObjects];
	return rxObjects;
}

// ---------------------------------------------- timerFireMethod --------------
- (void)timerFireMethod:(NSTimer*)theTimer
{
	@try {
		if (self && bTimerEnabled && dataset != nil) {
			if (nowTime != nil) {
				[nowTime setDateValue:[NSDate date]];
			} 
			[self updateForecast];
		}
	}
	@catch (NSException * e) {
		[timer invalidate];
	}
}

// ---------------------------------------------- updateForecast ---------------
// Update the time shown in the next-time clock, and stop/start the alarm sound
// aEvents is an array of RXEvents
- (void)updateForecast
{
	NSArray* aEvents;
	NSTimeInterval nextInterval = [[dataset forecast] updateForecastsReturningRXEvents:&aEvents];
	[rxeList reloadData];
	[rxeController setSelectedObjects:aEvents];
	[nextTime setDateValue:[NSDate dateWithTimeIntervalSinceNow:nextInterval]];
	
	[[dataset forecast] updateDailyIntervals];
	
	if (nextInterval <= 0 && ![sAlarm isPlaying]) {
		[sAlarm play];
	}
	else if (nextInterval > 0 && [sAlarm isPlaying]) {
		[sAlarm stop];
	}
}

// ---------------------------------------------- updateForecastForRX ----------
// Remove any forecasts for this RX, then make a new one
- (void)updateForecastForRX:(RX*)anRx
{
	NSDate* now = [NSDate date];
	RXEvent* rxe = nil;
	for (int ix = 0; ix < [[dataset forecast] count]; ++ix) {
		RXEvent* testRxe = [[dataset forecast] objectAtIndex:ix];
		if ([testRxe rx] == anRx) {
			rxe = testRxe;
			[rxe setTimestamp:now];
			break;
		}
	}
	if (rxe == nil) {
		rxe = [[dataset forecast] createRXEventForRX:anRx withDate:now];
		[rxeController addObject:rxe];
	}
	[rxe populateRXEventUsingDataSet:dataset];
}

#pragma mark -
#pragma mark Printing
// =============================================================================
// ---------------------------------------------- printOperationWithSettings:error:
- (NSPrintOperation*)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError
{
	NSPrintInfo* printInfo = [self printInfo];
	NSView*theView = [[NSTextView alloc] initWithFrame:[printInfo imageablePageBounds]];
	[self printForecastToView:theView];
	//[printInfo setOrientation:NSLandscapeOrientation];
	[printInfo setScalingFactor:0.68];
	NSPrintOperation* printOp = [NSPrintOperation printOperationWithView:theView printInfo:printInfo];
	return printOp;
}

#pragma mark -
#pragma mark Projection sheet
// =============================================================================
// ---------------------------------------------- printForecastToView ----------
- (void)printForecastToView:(NSView*)v
{
	
	NSString* headerText = [NSString stringWithFormat:@"\nSchedule as of %@\n\n", [NSDate date]];
	NSMutableAttributedString* header = [[[NSMutableAttributedString alloc] 
										  initWithString:headerText]
										 autorelease];
	[header addAttribute:NSFontAttributeName
				   value:[NSFont userFontOfSize:18]
				   range:NSMakeRange(0, [header length]-1)];
	[v insertText:header];
	[[dataset forecast] textOutputScheduleToView:v withDataset:dataset];
}

// ---------------------------------------------- showCustomSheet --------------
- (void)showCustomSheet: (NSWindow *)window
{
    if (!myCustomSheet){
        [NSBundle loadNibNamed: @"ProjectionSheet" owner: self];
	}
    [NSApp beginSheet: myCustomSheet
	   modalForWindow: window
		modalDelegate: self
	   didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
		  contextInfo: nil];
	
	[self printForecastToView:csText];
}

- (IBAction)closeMyCustomSheet: (id)sender
{
    [NSApp endSheet:myCustomSheet];
}

- (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
    [sheet orderOut:self];
}

// ---------------------------------------------- myWindow ---------------------
- (NSWindow*)myWindow
{
	NSWindow* window = [[[self windowControllers] objectAtIndex:0] window];
	return window; 
}

// ---------------------------------------------- setEditedStatus --------------
- (void)setEditedStatus
{
	// FIXME:Remove when UndoManager implemented
	[self updateChangeCount:NSChangeDone];
}

// ---------------------------------------------- setEditedStateToBe -----------
- (void)setEditedStateToBe:(BOOL)state
{
	// FIXME:Remove when UndoManager implemented
	if (!state) {
		[self updateChangeCount:NSChangeCleared];
	}
}

#pragma mark -
#pragma mark Boilerplate code from XCode
// =============================================================================
// ---------------------------------------------- close ------------------------
- (void)close
{
	bTimerEnabled = NO;
	[super close];
}

// ---------------------------------------------- dealloc ----------------------
- (void)dealloc
{
	bTimerEnabled = NO;
	[dataset release];
	dataset = nil;
	[sAlarm release];
	sAlarm = nil;
	[super dealloc];
}

// ---------------------------------------------- init -------------------------
- (id)init
{
    self = [super init];
    if (self) {
		dataset = [[DataSet alloc] init];
		if (dataset == nil) {
			[self release];
			return nil;
		}
		bTimerEnabled = NO;
		timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 //UPDATEINTERVAL 
												 target: self
											   selector: @selector(timerFireMethod:) 
											   userInfo: self
												repeats: YES];
		sAlarm = [NSSound soundNamed:@"Blow"];
		[sAlarm setLoops:YES];
		// FIXME:Remove when UndoManager implemented
		[self setHasUndoManager:NO];
	}
    return self; 
}

// ---------------------------------------------- windowNibName ----------------
- (NSString *)windowNibName
{
    // Override returning the nib file name of the document
    // If you need to use a subclass of NSWindowController or if your document 
	// supports multiple NSWindowControllers, you should remove this method and 
	// override -makeWindowControllers instead.
    return @"MyDocument";
}

// ---------------------------------------------- windowControllerDidLoadNib ---
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];
    // Add any code here that needs to be executed once the windowController has 
	// loaded the document's window.
	[datePicker setDateValue:[NSDate date]];
	// FIXME:May need to remove when UndoManager implemented
	[aController setShouldCloseDocument:YES];
	[self makeLatestHistoryVisible];
}

#pragma mark -
#pragma mark File I/O
// =============================================================================
-(BOOL)keepBackupFile
{
	return YES;
}

// ---------------------------------------------- dataOfType -------------------
// Writes to file
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
	NSData* d;
	
	@try{
		d = [NSKeyedArchiver archivedDataWithRootObject:dataset];
	}
	@catch (id obj) {
		if (outError != NULL ) {
			*outError = [NSError errorWithDomain:NSOSStatusErrorDomain 
											code:unimpErr 
										userInfo:NULL];
		}
		d = nil;
	}
	if (d != nil) {
		[self setEditedStateToBe:NO];
	}
	return d;
}

// ---------------------------------------------- readFromData:ofType:error: ---
// Reads from file
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
	DataSet* ds = nil;
	
	@try {
		ds = [NSKeyedUnarchiver unarchiveObjectWithData:data];
		[[dataset arrayMeds] validateObject];
	}
	@catch (id obj) {
		if (outError) {
			NSDictionary *d = [NSDictionary dictionaryWithObject:@"This file is corrupted."
														  forKey:NSLocalizedFailureReasonErrorKey];
			*outError = [NSError errorWithDomain:NSOSStatusErrorDomain 
											code:unimpErr 
										userInfo:d];
		}
		return NO;
	}
	
	[self setDataset:ds];
    return YES;
}

// ---------------------------------------------- readiPadStreamMenu -----------
- (IBAction)readiPadStreamMenu:(id)sender
{
	[self loadFileData];
}

// -----------------------------------------------------------------------------
// Aborts on error if no error response requested
- (NSString*)getImportData:(NSError**)e
{
    NSString* csvPath = @"ftp://imed:imed@%@/foo.csv";
    NSString* v = [[NSUserDefaults standardUserDefaults] stringForKey:@"csvHost"];
	if (!v || [v length] == 0) {
		v = @"localhost";
	}
    NSString* t = [NSString stringWithFormat:csvPath, v];
    NSURL *url = [NSURL URLWithString:t];
	NSError* error = nil;
    NSString* s = [NSString stringWithContentsOfURL:url 
										   encoding:NSASCIIStringEncoding 
											  error:&error];
    if (error != nil) {
		NSLog(@"Error in getImportData: %@", [error userInfo]);
		s = nil;
		if (e != nil) {
			*e = error;
		}
		else {
			abort();
		}
    }
    return [s retain];
}

- (void)alert:(NSString*)title withMessage:(NSString*)msg
{
	NSRunInformationalAlertPanel(title, 
								 msg,
								 @"OK", 
								 NULL, NULL);
	
}
// -----------------------------------------------------------------------------
- (void)loadFileData
{
	@try {
		NSError* error;
		NSString* stringFromFileAtPath = [self getImportData:&error];
		//NSLog(@"File length: %d, is %@", [stringFromFileAtPath length], stringFromFileAtPath);
		
		if (stringFromFileAtPath != nil) {
			NSScanner* scan = [NSScanner scannerWithString:stringFromFileAtPath];
			NSCharacterSet *anum = [[NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789"] retain];
			NSCharacterSet *quote = [[NSCharacterSet characterSetWithCharactersInString:@"\"\\n "] retain];
			NSCharacterSet *punc = [[NSCharacterSet punctuationCharacterSet] retain];
			NSCharacterSet *dtime = [[NSCharacterSet characterSetWithCharactersInString:@"JanFebMarAprMayJunJulAugSepOctNovDecAMPMampm:0123456789- "] retain];
			NSDateFormatter *df = [[NSDateFormatter alloc] init];
			[df setDateFormat:@"MMM-d-yyyy hh:mm a"];
			[df setDefaultDate:[NSDate date]];
			//NSLog(@"Date string |%@|", [df stringFromDate:[NSDate date]]);
			while (![scan isAtEnd]) {
				NSString* foo;
				BOOL bQuote = [scan scanCharactersFromSet:quote intoString:&foo];
				if (!bQuote && [foo length] == 0) {
					break;
				}
				else if (!bQuote && [foo length] > 0) {
					NSLog(@"Mis-parse: [%@]", foo);
					[self alert:@"Fail" withMessage:@"Didn't find expected quote string in dataset"];
					break;
				}
				NSString* sName;
				NSString* sDate;
				[scan scanCharactersFromSet:anum intoString:&sName];
				[scan scanCharactersFromSet:punc intoString:NULL];
				[scan scanCharactersFromSet:dtime intoString:&sDate];
				NSDate *d = [df dateFromString:sDate];
				RX* anRX = [RX findString:sName];
				//NSLog(@"Found date %@ and RX %@", d, anRX);
				if (anRX != nil) {
					if (d == nil) {
						[self alert:@"Failed" withMessage:@"Failed to parse date in CSV file"];
						break;
					}
					NSAssert(d != nil, @"Date failure loading");
//					NSLog(@"Name: |%@| at Time: %@", anRX, d);
					
					History* prior = [[CURRENTDATASET history] priorRXHistory:anRX];
					if (!prior || [d isGreaterThan:[prior timestamp]]) {
						[self createHistoryForRX:anRX atTime:d];
						[self setEditedStatus];
					}
					
				}
				else {
					NSLog(@"Failed to find %@", anRX);
					break;
				}

			}
			[anum release];
			[quote release];
			[punc release];
			[dtime release];
			[df release];
			[stringFromFileAtPath release];
		}
		else {
			NSLog(@"Open failed, error is: %@", [error userInfo]);
			[self alert:@"Open failed" withMessage:@"Could not load data from file."];
		}
	}
	@catch (NSException * e) {
		[self alert:@"Error caught." withMessage:[[e userInfo] description]];
	}
}

// ---------------------------------------------- writeNumbersCountsMenu -------
- (IBAction)writeNumbersCountsMenu:(id)sender
{
	[self writeCSVToFile:@"~/Documents/iMed Data/counts.csv" detail:NO counts:YES stream:NO];
}

// ---------------------------------------------- writeHistoryDetailMenu -------
- (IBAction)writeHistoryDetailMenu:(id)sender
{
	[self writeCSVToFile:@"~/Documents/iMed Data/detail.csv" detail:YES counts:NO stream:NO];
}

// ---------------------------------------------- writeiPadStreamMenu ----------
- (IBAction)writeiPadStreamMenu:(id)sender
{
	[self writeCSVToFile:@"~/Documents/iMed Data/foo.csv" detail:NO counts:NO stream:YES];
}

NSDate* nilDate = nil;
// ---------------------------------------------- writeCSVToPath ---------------
- (BOOL)writeCSVToFile:(NSString*)aPath detail:(BOOL)bDetail counts:(BOOL)bCounts stream:(BOOL)bStream
{
	NSCalendar* c = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
	if (nilDate == nil) {
		nilDate = [NSDate distantPast];
	}
	NSMutableDictionary* summary = [[[NSMutableDictionary alloc] init] autorelease];
	NSString* exPath = [aPath stringByExpandingTildeInPath];
	NSLog(@"%@",exPath);
	FILE* fOut = fopen([exPath UTF8String], "w");
	if (fOut == NULL) {
		NSRunInformationalAlertPanel(@"I/O Error", 
									 [NSString stringWithFormat:@"Could not create file\"%@\"", exPath],
									 @"Fix it", 
									 NULL, NULL);
		return NO;
	}
	BOOL bOK = YES;
	NSArray* sRXArray = [[NSArray alloc] initWithObjects:
						 [[dataset arrayRXlog] objectWithName:@"Lyrica"], 
						 [[dataset arrayRXlog] objectWithName:@"Celebrex"], 
						 [[dataset arrayRXlog] objectWithName:@"Oxycontin"], 
						 [[dataset arrayRXlog] objectWithName:@"Percocet"], 
						 nil];

	if (bDetail || bCounts) {
		fprintf(fOut, "Date/Time");
		for (int ix = 0; ix < [sRXArray count]; ++ix) {
			RX* rx = (RX*)[sRXArray objectAtIndex:ix];
			const char* s = [rx.ndc.name UTF8String];
			fprintf(fOut, ", %s", s);
		}
		fprintf(fOut, "\n");
	}
	
	//TODO: Build a dictionary by day of RX's, and for each RX record the count
	NSDate* current = nil;
	HistoryLog* log = [dataset history];
	id nils[] = {nilDate, nilDate, nilDate, nilDate};
	NSArray* arrayNils = [[NSArray alloc] initWithObjects:nils count:4];
	NSMutableArray* sRXTimesArray = [[NSMutableArray alloc] initWithArray:arrayNils];
	NSUInteger i, count = [log count];
	BOOL bPrintDate = YES;
	for (i = 0; i < count; i++) {
		History* obj = [log objectAtIndex:i];
		if (bStream) {
			fprintf(fOut, "\"%s\" %s %s\n", 
					[obj.rx.ndc.name UTF8String],
					[[self dateToNSString:obj.timestamp] UTF8String],
					[self csvOutFormatInterval:obj.timestamp]);
		}
		int ix = [sRXArray indexOfObject:obj.rx];
//		NSString* name = [NSString stringWithFormat:@"Bad ix for rx %@", obj.rx.ndc.name];
//		NSAssert(ix <= [sRXArray count], name);
		if (ix >= 0 && ix < [sRXArray count]) {
			NSDate* thisDate = obj.timestamp;
			NSString* thisDay = [[c dateFromComponents:[dataset dayForDate:thisDate]] description];
			BOOL bSameDate = [dataset isDate:thisDate onSameDayAsDate:current];
			if (!bSameDate) {
				NSMutableArray* n = [[NSMutableArray alloc] initWithObjects:
									 [NSNumber numberWithInt:0], 
									 [NSNumber numberWithInt:0],
									 [NSNumber numberWithInt:0],
									 [NSNumber numberWithInt:0],nil];
				[summary setValue:n forKey:thisDay];
			}

			@try {
				[[summary objectForKey:thisDay] replaceObjectAtIndex:ix 
														  withObject:[NSNumber numberWithInt:[[(NSMutableArray*)[summary objectForKey:thisDay] objectAtIndex:ix] intValue]+1]];
			}
			@catch (NSException * e) {
				NSAssert(NO, @"Failed");
			}
			if (!bSameDate || [sRXTimesArray objectAtIndex:ix] != nilDate) {
				if (bDetail) {
					[self csvOutToFile:fOut 
									 T:bPrintDate ? current : nilDate
									 A:[sRXTimesArray objectAtIndex:0] 
									 B:[sRXTimesArray objectAtIndex:1]
									 C:[sRXTimesArray objectAtIndex:2]
									 D:[sRXTimesArray objectAtIndex:3]];
				}
				[sRXTimesArray setArray:arrayNils];
				current = thisDate;
				bPrintDate = !bSameDate;
			}
			[sRXTimesArray replaceObjectAtIndex:ix withObject:thisDate];
		}
	}
	if (bDetail) {
		[self csvOutToFile:fOut 
						 T:bPrintDate ? current : nilDate
						 A:[sRXTimesArray objectAtIndex:0] 
						 B:[sRXTimesArray objectAtIndex:1] 
						 C:[sRXTimesArray objectAtIndex:2] 
						 D:[sRXTimesArray objectAtIndex:3]];
	}

	if (bCounts) {
		NSEnumerator *enumerator = [summary keyEnumerator];
		id key;
		
		while ((key = [enumerator nextObject])) {
			NSArray* a = [summary objectForKey:key];
			NSDate* d = [NSDate dateWithString:key];
			fprintf(fOut, "%s,%d, %d, %d, %d\n", 
					[[self dateToNSString:d] UTF8String]
					, [[a objectAtIndex:0] intValue]
					, [[a objectAtIndex:1] intValue]
					, [[a objectAtIndex:2] intValue]
					, [[a objectAtIndex:3] intValue]);
		}
	}

	fclose(fOut);
	
	return bOK;
}
static NSDateFormatter* dateFmt = nil;
// ---------------------------------------------- dateToNSString ---------------
- (NSString*)dateToNSString:(NSDate*)t
{
	if (dateFmt == nil) {
		dateFmt = [[NSDateFormatter alloc] init] ;
		[dateFmt setDateFormat:@"MMM-dd-yyyy"];
	}
	return (t != nil) ? [dateFmt stringFromDate:t] : nil;
}

// ---------------------------------------------- csvOutToFile:A:B:C:D ---------
- (void)csvOutToFile:(FILE*)fOut T:(NSDate*)t A:(NSDate*)a B:(NSDate*)b C:(NSDate*)c D:(NSDate*)d
{
	if (t != nil) {
//		printf("%s,%s,%s,%s,%s\n", 
		fprintf(fOut, "%s,%s,%s,%s,%s\n", 
			   (t != nilDate) ? [[self dateToNSString:t] UTF8String] : "",
			   [self csvOutFormatInterval:a], 
			   [self csvOutFormatInterval:b], 
			   [self csvOutFormatInterval:c], 
			   [self csvOutFormatInterval:d] );
	}
}

static NSDateFormatter* timeFmt = nil;
// ---------------------------------------------- csvOutFormatInterval ---------
- (const char*)csvOutFormatInterval:(NSDate*)v
{
	if (timeFmt == nil) {
		timeFmt = [[NSDateFormatter alloc] init] ;
		[timeFmt setDateFormat:@"h:mm a"];
	}
	const char* s;
	if (v != nilDate) {
		s = [[timeFmt stringFromDate:v] UTF8String];
	}
	else {
		s = "";
	}

	return s;
}

#pragma mark -
#pragma mark Element preload 
// =============================================================================
// ---------------------------------------------- preloadNDC -------------------
- (void)preloadNDC
{
	NDCitem* ndc;
	
	// Create some underlying populated data elements 
	ndc = [[[NDCitem alloc] initWithNDC:@"65505*107" 
								   Name:@"Oxycontin" 
							   Quantity:@"80" 
								   Unit:@"mg"] autorelease];
	[ndcController addObject:ndc];
	ndc = [[[NDCitem alloc] initWithNDC:@"00406-0523" 
								   Name:@"Percocet" 
							   Quantity:@"325;10" 
								   Unit:@"mg;mg"] autorelease];
	[ndcController addObject:ndc];
	ndc = [[[NDCitem alloc] initWithNDC:@"00025-1525" 
								   Name:@"Celebrex" 
							   Quantity:@"200" 
								   Unit:@"mg"] autorelease];
	[ndcController addObject:ndc];
	ndc = [[[NDCitem alloc] initWithNDC:@"00071-1016" 
								   Name:@"Lyrica" 
							   Quantity:@"150" 
								   Unit:@"mg" ] autorelease];
	[ndcController addObject:ndc];
	ndc = [[[NDCitem alloc] initWithNDC:@"00024-5521" 
								   Name:@"Ambien CR" 
							   Quantity:@"12.5" 
								   Unit:@"mg" ] autorelease];
	[ndcController addObject:ndc];
}

// ---------------------------------------------- preloadRX --------------------
- (void)preloadRX
{
	RX* rx;
	
	rx = [[[RX alloc] initWithDateWritten:[NSDate date] 
							   dateFilled:[NSDate date] 
									  Ndc:[[dataset arrayMeds] objectWithName:@"Oxycontin"]
									 Dose:(float)1.0
								 Interval:(double)4.14*HOUR] autorelease];
	[rxController addObject:rx];
	
	rx = [[[RX alloc] initWithDateWritten:[NSDate date] 
							   dateFilled:[NSDate date] 
									  Ndc:[[dataset arrayMeds] objectWithName:@"Percocet"]
									 Dose:(float)0.5
								   Perday:(float)7.0] autorelease];
	[rxController addObject:rx];
	
	rx = [[[RX alloc] initWithDateWritten:[NSDate date] 
							   dateFilled:[NSDate date] 
									  Ndc:[[dataset arrayMeds] objectWithName:@"Celebrex"]
									 Dose:(float)1.0
								   Perday:(float)3.0] autorelease];
	[rxController addObject:rx];
	
	rx = [[[RX alloc] initWithDateWritten:[NSDate date] 
							   dateFilled:[NSDate date] 
									  Ndc:[[dataset arrayMeds] objectWithName:@"Lyrica"]
									 Dose:(float)1.0
								   Perday:(float)2.0] autorelease];
	[rxController addObject:rx];
	
	rx = [[[RX alloc] initWithDateWritten:[NSDate date] 
							   dateFilled:[NSDate date] 
									  Ndc:[[dataset arrayMeds] objectWithName:@"Ambien CR"]
									 Dose:(float)1.0
								   Perday:(float)1.0] autorelease];
	[rxController addObject:rx];
}

/*
 NSRunInformationalAlertPanel(@"Date Error", 
 @"Date precedes history entry for this RX", 
 @"Fix it", 
 NULL, NULL);
 */

@synthesize dataset;
@synthesize rxeController;
@synthesize ndcController;
@synthesize rxController;

@end
